/* Copyright © 2010 LPRM
Universidade Federal do Espírito Santo - RNP-GT CWTools

This file is part of GW-Android.

GW-Android is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

GW-Android is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GW-Android. If not, see <http://www.gnu.org/licenses/>. */
package br.ufes.cwtools.android;

import java.io.IOException; 
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

public class MainActivity extends Activity {
	private static final String TAG = "MainActivity";

//	private static final String URL_TEST_LOGO = "http://i.imgur.com/gTnQG.jpg";
	private static final String URL_TEST_LOGO = "";

	private static final String KEY_ACTIONS_LIST = "a";
	private static final String KEY_CURRENT_ACTION = "b";
	
	private static final int REQUEST_CODE_FIRST_ACTION = 100;
	
	private Action currentAction = null;
	private List<Action> actions = null;
	
	@SuppressWarnings("unchecked") // Por causa do cast com generics.
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.base);
		
		// Autentica o usuário.  // TODO Pode ser demorado, talvez seja melhor fazer em outro momento (de forma assíncrona).
		String login = this.getIntent().getStringExtra(GroupwareClient.EXTRA_SERVER_LOGIN);
		String password = this.getIntent().getStringExtra(GroupwareClient.EXTRA_SERVER_PASSWORD);
		((ComApplication) this.getApplication()).authenticateUser(login, password);
		
//		String serverName = this.getIntent().getStringExtra(GroupwareClient.EXTRA_SERVER_NAME);
//		String serverUrl = this.getIntent().getStringExtra(GroupwareClient.EXTRA_SERVER_URL);
		
		// Recupera o estado salvo em uma mudança de orientação da tela.
		Map<String, Object> state = (Map<String, Object>) this.getLastNonConfigurationInstance();
		if (state != null) {
			// Recupera a lista de ações; poupa ter que baixar e processar novamente o XML.
			this.actions = (List<Action>) state.get(KEY_ACTIONS_LIST);
			// Recupera a ação corrente.
			this.currentAction = (Action) state.get(KEY_CURRENT_ACTION);
		}
		if (actions == null) {
			// Carrega os componentes e ações disponíveis a partir do xml.
			this.actions = loadActions();
		}
		
		// Cria as views com os botões para as ações.
		LinearLayout container = (LinearLayout) this.findViewById(R.id.buttons_container);
		for (Action action : actions) {
			View view = getLayoutInflater().inflate(R.layout.action_menu_item, null);
			container.addView(view);
			
			Log.d(TAG, "Registered action '" + action.getName() + "'.");
			Button button = (Button) view.findViewById(R.id.button);
			button.setText(action.getName());
			button.setTag(action);
		}
		
		// Nome da aplicação.  // TODO
		((TextView) findViewById(R.id.title)).setText("Arquigrafia");
		
		// Carrega o logo a ser exibido a partir de uma URL e coloca na view.  // TODO
//		Drawable d = MainActivity.retrieveImageDrawable(URL_TEST_LOGO);
//		if (d != null) {
//			ImageView logoImageView = (ImageView) this.findViewById(R.id.logo);
//			logoImageView.setImageDrawable(d);
//			logoImageView.setVisibility(View.VISIBLE);
//		}
		// TODO Maquiagem.
		ImageView logoImageView = (ImageView) this.findViewById(R.id.logo);
		logoImageView.setImageResource(R.drawable.arquigrafia);
		logoImageView.setVisibility(View.VISIBLE);
		((TextView) findViewById(R.id.title)).setVisibility(View.GONE);
		findViewById(R.id.base).setBackgroundColor(Color.WHITE);
	}
	
	@Override
	public Object onRetainNonConfigurationInstance() {
		// Guarda o estado atual em caso de uma mudança na orientação da tela;
		// não tratará os casos em que esta atividade é terminada por alguma razão.
		// TODO Testar isso com o telefone.
		
		Map<String, Object> state = new HashMap<String, Object>();
		state.put(KEY_CURRENT_ACTION, this.currentAction);
		state.put(KEY_ACTIONS_LIST, this.actions);
		return state;
	}
	
	private List<Action> loadActions() {
		// TODO Baixar o xml do servidor selecionado ao invés de usar um raw resource.
		InputStream source = this.getResources().openRawResource(R.raw.sample_application);
		GwApplication app = GwApplicationParser.parse(source);
		List<Action> actions = new LinkedList<Action>();
		if (app != null) {
			actions.addAll(app.actions.values());
		}
		return actions;
	}
	
	public void buttonOnClick(View view) {
		this.currentAction = (Action) view.getTag();
		Log.d(TAG, "Starting action '" + currentAction.getName() + "'.");
		Intent intent = new Intent();
		startComponentActivity(intent, currentAction, REQUEST_CODE_FIRST_ACTION);
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		if (resultCode == RESULT_CANCELED) {
			Log.d(TAG, "Activity finished, result CANCELED.");
		} else if (resultCode == Component.RESULT_BACK) {
			Log.d(TAG, "Activity finished, result BACK.");
//			if (requestCode > FIRST_ACTION_STEP) {
//				startComponentActivity(data, action, requestCode - 1);
//			} else return;
		} else if (resultCode == RESULT_OK && requestCode >= REQUEST_CODE_FIRST_ACTION) {
			startComponentActivity(data, currentAction, requestCode + 1);
		}
	}
	
	private void startComponentActivity(Intent intent, Action action, int step) {
		if (action == null) {
			Log.w(TAG, "Current action is null (did we lost our action instance?)");
			return;
		}
		if (intent == null) intent = new Intent();
		Log.d(TAG, "Starting component activity for action " + action.getName() + ", component " + (step - REQUEST_CODE_FIRST_ACTION) + ".");
		ComponentDefinition component = action.getComponent(step - REQUEST_CODE_FIRST_ACTION);
		if (component == null) {
			Log.d(TAG, "Component not found (last component reached?)");
			this.currentAction = null;
			return;
		}
		Log.d(TAG, "Starting component " + component.getName() + ", class " + component.getClassName() + ".");
		intent.setClassName(component.getPackage(), component.getClassName());
		startActivityForResult(intent, step);
	}
	
	/**
	 * @param imageUrl URL da imagem a ser carregada.
	 * @return Drawable contendo a imagem carregada ou null em caso de falha.
	 */
	private static Drawable retrieveImageDrawable(String imageUrl) {
		try {
			URL url = new URL(imageUrl);
			InputStream is = (InputStream) url.getContent();
			return Drawable.createFromStream(is, "logo");
		} catch (MalformedURLException e) {
			return null;
		} catch (IOException e) {
			return null;
		}
	}
}

class Action {
	List<ComponentDefinition> components;
	String name;
	
	public Action(String name) {
		this.name = name;
		this.components = new LinkedList<ComponentDefinition>();
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void addComponent(ComponentDefinition component) {
		this.components.add(component);
	}
	
	public ComponentDefinition getComponent(int i) {
		return i < components.size() ? components.get(i) : null;
	}
}

class ComponentDefinition {
	String name;
	String className;
	String packageName;
	
	public ComponentDefinition(String name, String className, String packageName) {
		this.name = name;
		this.className = className;
		this.packageName = packageName;
	}
	
	public String getName() {
		return name;
	}
	
	public String getClassName() {
		return className;
	}
	
	public String getPackage() {
		return packageName;
	}
}

class GwApplication {
	Map<String, ComponentDefinition> components;
	Map<String, Action> actions;
	
	public GwApplication() {
		this.components = new HashMap<String, ComponentDefinition>();
		this.actions = new HashMap<String, Action>();
	}
	
	public void putComponent(String tag, ComponentDefinition component) {
		this.components.put(tag, component);
	}
	
	public ComponentDefinition getComponent(String tag) {
		return this.components.get(tag);
	}

	public void putAction(String tag, Action action) {
		this.actions.put(tag, action);
	}
	
	public Action getAction(String tag) {
		return this.actions.get(tag);
	}
}
